package com.example.logaspect.aspect;

import com.example.logaspect.annotation.LogRecord;
import com.example.logaspect.annotation.LogRecord.LogLevel;
import com.example.logaspect.config.LogAspectProperties;
import com.example.logaspect.service.DefaultLogRecordServiceImpl;
import com.example.logaspect.service.LogRecordService;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order;

import java.lang.reflect.Method;
import java.util.Arrays;

/**
 * 基于注解的日志切面
 * @author Senhai Xu
 */
@Aspect
@Order(1)
public class AnnotationLogAspect {

    private final LogRecordService logRecordService;
    private final LogAspectProperties properties;


    public AnnotationLogAspect(LogRecordService logRecordService, LogAspectProperties properties) {
        this.logRecordService = logRecordService;
        this.properties = properties;
    }

    @Around("@annotation(com.example.logaspect.annotation.LogRecord)")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        // 如果切面被禁用，直接执行目标方法

        if (!properties.isEnabled() || !properties.isEnableAnnotationAspect()) {
            System.out.println("AnnotationLogAspect.around: log aspect is disabled");
            return joinPoint.proceed();
        }

        // 获取方法签名
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();

        // 获取方法上的注解
        LogRecord logRecord = method.getAnnotation(LogRecord.class);
        String description = logRecord.description();
        boolean recordParams = logRecord.recordParams();
        boolean recordResult = logRecord.recordResult();
        boolean recordExecutionTime = logRecord.recordExecutionTime();
        LogLevel level = logRecord.level();

        // 方法入参
        Object[] args = joinPoint.getArgs();
        String methodSignature = method.getDeclaringClass().getName() + "." + method.getName();

        // 记录方法开始执行
        if (recordParams) {
//            debug:不产生输出
            logRecordService.recordMethodStart(methodSignature, description, args, level);
        } else {
            logRecordService.recordMethodStart(methodSignature, description, null, level);
        }

        // 执行时间
        long startTime = System.currentTimeMillis();
        Object result = null;
        try {
            // 执行目标方法
            result = joinPoint.proceed();

            // 计算执行时间
            long executionTime = System.currentTimeMillis() - startTime;

            // 记录方法执行完成
            if (recordExecutionTime) {
                if (recordResult) {
                    logRecordService.recordMethodEnd(methodSignature, description,
                            recordParams ? args : null,
                            result, executionTime, level);
                } else {
                    logRecordService.recordMethodEnd(methodSignature, description,
                            recordParams ? args : null,
                            null, executionTime, level);
                }
            }

            return result;
        } catch (Throwable throwable) {
            // 记录异常
            long executionTime = System.currentTimeMillis() - startTime;
            logRecordService.recordMethodException(methodSignature, description,
                    recordParams ? args : null,
                    throwable, executionTime, level);
            throw throwable;
        }
    }
}